﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;

namespace lib_1241108_1241150
{
    public class KMeanAlg
    {
        private DataTable dtb = new DataTable(); //dư trử dữ liệu để tính toán.
        private DataTable dtAfterNor = new DataTable();

        private List<bool> isDataNumber = new List<bool>(); //lưu xem giá trị nó là nominal hay real

        private List<double> min = new List<double>();
        private List<double> max = new List<double>();

        private int soK;

        public DataTable Dtb
        {
            get { return dtb; }
        }

        /// <summary>
        /// Hàm này dùng để khởi tạo dữ liệu dùng để tính toán, dữ liệu đọc được sẽ được lưu trong thuộc tính Dtb 
        /// </summary>
        /// <param name="urlFile">Đường dẫn URL tới File đó</param>
        /// <param name="missingValue">kí tự đại diện cho giá trị bị thiếu trong tập tin</param>
        /// <returns>trả về cái chuổi để hiện trên messagebox </returns>
        public string InitClassAndReadFile(string urlFile, char missingValue)
        {
            //Kiểm tra xem đường dẫn có hợp lệ hông.
            if (!File.Exists(urlFile))
                return "File is not exists";

            StreamReader reader = new StreamReader(urlFile);

            try
            {
                string line = reader.ReadLine();
                bool isData = false;

                while (line != null)
                {
                    this.InsertDataToDataTable(line, ref isData, missingValue);

                    line = reader.ReadLine();
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }

            return "Read file is success!";
        }


        /// <summary>
        /// Hàm dùng để đưa dữ liệu vào datatable
        /// </summary>
        /// <param name="line">1 dòng đọc được từ dữ liệu</param>
        /// <param name="isData">xét xem nó phải là dữ liệu hông</param>
        /// <param name="missingValue">định nghĩa dữ liệu bị thiếu</param>
        private void InsertDataToDataTable(string line, ref bool isData, char missingValue)
        {
            // bỏ qua mấy dòng ghi chú
            if (line.Count() == 0 || line[0] == '%')
            {
                return;
            }

            // lấy nhưng dòng attributes và gáng nó thành tên cột.
            if (line.Split(' ', '\t')[0].Equals("@ATTRIBUTE"))
            {
                string lineName = line.Split(' ', '\t')[1].Replace("'", "");
                bool isReal = line.Contains("real") || line.Contains("REAL") || line.Contains("Real") ;

                isDataNumber.Add(isReal);

                DataColumn dtc = new DataColumn(lineName, isReal ? typeof(double) : typeof(string));

                dtc.AllowDBNull = true;

                dtb.Columns.Add(dtc);
            }

            //Kiểm tra đã bắt đầu tới dữ liệu chưa
            if (line.Contains("@DATA") || (line.Contains("@data")))
            {
                //tới rồi thì bật data lên để biết.
                isData = true;
                return;
            }

            // lấy những dòng dữ liệu đưa vào datatable
            if (isData)
            {
                //bắt đầu đọc data.    
                //Cắt chuổi ra thành từng ô nhỏ.
                string[] data = line.Split(',');
                DataRow dtr = dtb.NewRow();

                //Init MIN-MAX
                if (dtb.Rows.Count == 1)
                    for (int i = 0; i < this.isDataNumber.Count; i++)
                        if (this.isDataNumber[i])
                        {
                            double temp = (double)dtb.Rows[0][i];
                            //khởi tạo min = max luôn cho tiện.

                            this.min.Add(temp);
                            this.max.Add(temp);
                        }
                        else
                        {
                            this.min.Add(0);
                            this.max.Add(0);
                        }
                

                for (int i = 0; i < data.Count(); i++)
                    if (isDataNumber[i])
                        //Dây là numberic
                        //Nếu là dữ liệu ? thì mình bỏ qua
                        if (!data[i].Contains(missingValue))
                        {
                            dtr[i] = double.Parse(data[i]);

                            this.min[i] = double.Parse(data[i]) > this.min[i] ? this.min[i] : double.Parse(data[i]);
                            this.max[i] = double.Parse(data[i]) > this.max[i] ? double.Parse(data[i]) : this.max[i];
                        }
                    else
                        //Đây là norminal
                        if (!data[i].Contains(missingValue))
                            dtr[i] = data[i].ToString();

                dtb.Rows.Add(dtr);
            }
        }

        public void DoKMeanAlg(int k)
        {

        }

        private double normalized(double input, double min, double max)
        {
            return (input - min) / (max - min);
        }

        private void CopyDataTableAndNormalized(DataTable input, ref DataTable output)
        {
            //Thêm cột
            for (int i = 0; i < input.Columns.Count; i++)
            {
                DataColumn dtc = input.Columns[i];

                output.Columns.Add(dtc);
            }

            //Thêm dòng

            for (int j = 0; j < input.Rows.Count; j++)
            {
                DataRow dtr = output.NewRow();

                for (int i = 0; i < input.Columns.Count; i++)
                {
                    if (this.isDataNumber[i])
                        dtr[i] = normalized((double)input.Rows[j][i], this.min[i], this.max[i]);
                    else
                        dtr[i] = input.Rows[j][i];

                }
                output.Rows.Add(dtr);
            }
        }
    }
}
